//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Malla.h"

PV3D* Malla::getVectorNormalPorNewell(Cara* c){
        float x = 0.0;
        float y = 0.0;
        float z = 0.0;
        int numVerticesC = c->getNumVertices();
        for (int i=0;i<numVerticesC;i++){
                PV3D* act = vertices[c->getIndiceVertice(i)];
                PV3D* sig = vertices[c->getIndiceVertice((i+1)%numVerticesC)];
                x = x + (act->getY() - sig->getY())*(act->getZ() + sig->getZ());
                y = y + (act->getZ() - sig->getZ())*(act->getX() + sig->getX());
                z = z + (act->getX() - sig->getX())*(act->getY() + sig->getY());
        }
        PV3D* p = new PV3D(x,y,z,0);
        p->normalizar();
        return p;
};

void Malla::dibuja(bool relleno,bool dibujarNormales){
        for(int i=0;i<numCaras;i++){
                glLineWidth(1.0);
                if (!relleno) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
                else glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
                glBegin(GL_POLYGON);
                double sumaX = 0;
                double sumaY = 0;
                double sumaZ = 0;
                for(int j=0;j<caras[i]->getNumVertices();j++){
                        int iN = caras[i]->getIndiceNormal(j);
                        int iV = caras[i]->getIndiceVertice(j);
                        glNormal3f(normales[iN]->getX(),normales[iN]->getY(),normales[iN]->getZ());
                        glVertex3f(vertices[iV]->getX(),vertices[iV]->getY(),vertices[iV]->getZ());
                        sumaX = sumaX + vertices[iV]->getX();
                        sumaY = sumaY + vertices[iV]->getY();
                        sumaZ = sumaZ + vertices[iV]->getZ();
                }
                glEnd();
                if (dibujarNormales){
                        int numV = caras[i]->getNumVertices();
                        sumaX = sumaX / numV;
                        sumaY = sumaY / numV;
                        sumaZ = sumaZ / numV;
                        PV3D* p = normales[caras[i]->getIndiceNormal(0)];
                        glBegin(GL_LINES);
                                glColor3f(1.0, 1.0, 1.0);
                                glVertex3f(sumaX,sumaY,sumaZ);
                                glVertex3f(sumaX-p->getX(),sumaY-p->getY(),sumaZ-p->getZ());
                                glColor3f(0.0, 0.0, 1.0);
                        glEnd();
                }

        }
};

void Malla::addVertice(PV3D* v){
        vertices[indiceV] = v;
        indiceV = indiceV + 1;
};

void Malla::addVertice(Rodaja* r){
        if (numVertices == indiceV)return;
        if (vertices == NULL) vertices = new PV3D*[numVertices];
        for(int i=0;i<r->getLados();i++){
                addVertice(r->getVertice(i)->clona());
        }
};
                              
void Malla::addCara(Cara* c){             
        if(numCaras == indiceC) return;
        caras[indiceC] = c;
        indiceC = indiceC + 1;   
};

void Malla::addNormal(PV3D* n){
        if (indiceN == numNormales) return;   
        normales[indiceN] = n;
        indiceN = indiceN + 1;
};

void Malla::addCaras(int num){
        int inicio = indiceV - 2*num;
        for (int i=0;i<num;i++){
                Cara* c = new Cara(4);
                c->addVN(i + inicio,0);
                c->addVN(((i+1)% num) + inicio,0);
                c->addVN(((i+1)% num)+ num + inicio,0);    
                c->addVN(i+num + inicio,0);
                addCara(c);
                PV3D* n = getVectorNormalPorNewell(c);
                addNormal(n);
                c->setNormales(indiceN-1);
        }
};

bool Malla::inicializado(){
        return numVertices>0 && numNormales>0 && numCaras>0;
};

PV3D* Malla::C(float t){
        return new PV3D(3*cos(t),2*cos(1.5*t),3*sin(t));
};

PV3D* Malla::dev1C(float t){
        return new PV3D(-3*sin(t),-3*sin(1.5*t),3*cos(t));
};

PV3D* Malla::dev2C(float t){
        return new PV3D(-3*cos(t),-4.5*cos(1.5*t),-3*sin(t));
};

PV3D* Malla::B(float t){
        PV3D* c1 = dev1C(t);
        PV3D* c2 = dev2C(t);
        c1 = c1->productoVectorial(c2);
        c1->normalizar();
        return c1;
};

PV3D* Malla::T(float t){
        PV3D* c1 = dev1C(t);
        c1->normalizar();
        return c1;
};
                                  
PV3D* Malla::N(float t){
       PV3D* b = B(t);
       PV3D* tt = T(t);
       b = b->productoVectorial(tt);
       return b;
};

Rodaja* Malla::transformacionM(Rodaja* r,float t){
        int lados = r->getLados();
        PV3D** v = new PV3D*[lados];
        PV3D* n = N(t);
        PV3D* b = B(t);
        PV3D* tt = T(t);
        PV3D* c = C(t);
        Rodaja* res = new Rodaja(lados);
        res->setRadio(r->getRadio());
        for (int i=0;i<lados;i++){
                PV3D* act = r->getVertice(i);
                float x = n->getX()*act->getX() + b->getX()*act->getY() +
                        tt->getX()*act->getZ() + c->getX();
                float y = n->getY()*act->getX() + b->getY()*act->getY() +
                        tt->getY()*act->getZ() + c->getY();
                float z = n->getZ()*act->getX() + b->getZ()*act->getY() +
                        tt->getZ()*act->getZ() + c->getZ();
                v[i] = new PV3D(x,y,z,1);
                res->setVertice(i,v[i]);
        }
        return res;
};

void Malla::clear(){
        if(vertices != NULL){
                for(int i=0;i<numVertices;i++){
                        delete vertices[i];
                        vertices[i] = NULL;
                }
        }

        if(normales != NULL){
                for(int i=0;i<numNormales;i++){
                        delete vertices[i];
                        vertices[i] = NULL;
                }
        }

        if(caras != NULL){
                for(int i=0;i<numCaras;i++){
                        delete caras[i];
                        caras[i] = NULL;
                }
        }
        indiceV = 0;
        indiceN = 0;
        indiceC = 0;
};

double * Malla::getMarcoFrenet(float t){
        PV3D* n = N(t);
        PV3D* b = B(t);
        PV3D* tt = T(t);
        PV3D* c = C(t);
        double* m = new double[16];
        m[0] = n->getX();
        m[1] = n->getY();
        m[2] = n->getZ();
        m[3] = 0;
        m[4] = b->getX();
        m[5] = b->getY();
        m[6] = b->getZ();
        m[7] = 0;
        m[8] = tt->getX();
        m[9] = tt->getY();
        m[10]= tt->getZ();
        m[11]= 0;
        m[12]= c->getX();
        m[13]= c->getY();
        m[14]= c->getZ();
        m[15]= 1;
        return m;
};

//---------------------------------------------------------------------------

#pragma package(smart_init)
 